﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Data.Linq;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI;
using System.Xml;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Portal.WebControls;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;
using Microsoft.Office.Server.UserProfiles;

namespace Ru.NoteBoardPlus
{
    public class NoteBoardPlusControl : SocialCommentControl, ICallbackEventHandler
    {
        /// <summary>
        /// Display note count
        /// </summary>
        public int DisplayItems
        {
            set
            {
                // SocialCommentControl.DisplayItems marked as internal, using reflection
                this.GetType().BaseType.GetProperty("DisplayItems", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, value);
            }
        }

        /// <summary>
        /// Override Note Board button event handler
        /// </summary>
        void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)
        {
            base.RaiseCallbackEvent(eventArgument);
            // Context parameters to use in a separate Task (thread)
            UserProfile oUserProfile = ProfileLoader.GetProfileLoader().GetUserProfile();
            string sUrl = this.Context.Request.Url.ToString();
            // Start Task
            Task.Run(() => NoteBoardPlusTask(eventArgument, oUserProfile, sUrl));
        }

        /// <summary>
        /// New Task (thread)
        /// </summary>
        /// <param name="eventArgument">Note Board button event handler parameters</param>
        /// <param name="UserProfile">Current user's profile</param>
        /// <param name="Url">Current page URL</param>
        private void NoteBoardPlusTask(string eventArgument, UserProfile UserProfile, string Url)
        {
            using (new SPMonitoredScope("NoteBoardPlus"))
            {
                // Parse XML input
                XmlDocument xmlDocument = new XmlDocument();
                using (XmlTextReader xmlTextReader = new XmlTextReader(new StringReader(eventArgument)))
                {
                    xmlTextReader.DtdProcessing = DtdProcessing.Prohibit;
                    xmlDocument.Load(xmlTextReader);
                }
                XmlElement xmlDocumentElement = xmlDocument.DocumentElement;
                // Send alert if operation type is Add or Edit
                string sType = xmlDocumentElement.GetAttribute("type");
                if ("Add".Equals(sType) || "Edit".Equals(sType))
                {
                    try
                    {
                        using (SPSite oSite = new SPSite(Url))
                        {
                            using (SPWeb oWeb = oSite.OpenWeb())
                            {
                                // Comment contents
                                XmlElement xmlComment = (XmlElement)xmlDocumentElement.SelectSingleNode("./RTEContents");
                                string sComment = SPHttpUtility.NoEncode(xmlComment.InnerText);
                                // Alert e-mail headers
                                StringDictionary oHeaders = new StringDictionary();
                                oHeaders.Add("content-type", "text/html");
                                // Get all alert recepient rules from configuration list
                                SPList oConfigList = oSite.RootWeb.GetList(oSite.RootWeb.ServerRelativeUrl.TrimEndSlash() + Constants.ConfigListUrl);
                                SPListItemCollection colRules = oConfigList.GetItems(new SPQuery() {
                                    Query = "<Where>" +
                                                "<IsNotNull><FieldRef Name=\"Title\" /></IsNotNull>" +
                                            "</Where>" +
                                            "<OrderBy>" +
                                                "<FieldRef Name=\"RulePriority\" Ascending=\"TRUE\"></FieldRef>" +
                                            "</OrderBy>",
                                    ViewFields = "<FieldRef Name=\"Title\" /><FieldRef Name=\"RuleRecepient\" /><FieldRef Name=\"RulePriority\" />",
                                    RowLimit = 2000
                                });
                                // Find rule recepients for current page
                                var colRecepients = (from SPListItem item in colRules
                                                     where Regex.IsMatch(Url, Convert.ToString(item["Title"]))
                                                     select item["RuleRecepient"] as SPFieldUserValueCollection).First();
                                // Add recepients to alert e-mail headers
                                StringBuilder oRecepients = new StringBuilder();
                                foreach (SPFieldUserValue oRuleRecepient in colRecepients)
                                    oRecepients.AppendFormat("{0},", oRuleRecepient.User.Email);
                                oHeaders.Add("to", oRecepients.ToString());
                                // Alert e-mail body
                                StringBuilder oBody = new StringBuilder();
                                switch (sType)
                                {
                                    case "Add":
                                        oHeaders.Add("subject", SPUtility.GetLocalizedString("$Resources:alert_Subject_New", Constants.ResourceFile, (uint)CultureInfo.CurrentUICulture.LCID));
                                        oBody.AppendFormat(SPUtility.GetLocalizedString("$Resources:alert_Body_New", Constants.ResourceFile, oWeb.Language),
                                            UserProfile.PublicUrl.AbsoluteUri, UserProfile.DisplayName, Url, oWeb.Url, oWeb.Title, sComment);
                                        break;

                                    case "Edit":
                                        oHeaders.Add("subject", SPUtility.GetLocalizedString("$Resources:alert_Subject_Update", Constants.ResourceFile, (uint)CultureInfo.CurrentUICulture.LCID));
                                        oBody.AppendFormat(SPUtility.GetLocalizedString("$Resources:alert_Body_Update", Constants.ResourceFile, oWeb.Language),
                                            UserProfile.PublicUrl.AbsoluteUri, UserProfile.DisplayName, Url, oWeb.Url, oWeb.Title, sComment);
                                        break;
                                }
                                SPUtility.SendEmail(oWeb, oHeaders, oBody.ToString());
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // Initialize ULS
                        SPDiagnosticsService oDiagnosticsSvc = SPDiagnosticsService.Local;
                        // Write to ULS
                        // Trace ID 942961785 - used in SocialCommentControl
                        // Diagnostics Category - SharePoint Foundation -> General
                        oDiagnosticsSvc.WriteTrace(942961785,
                            oDiagnosticsSvc.Areas["SharePoint Foundation"].Categories["General"],
                            TraceSeverity.Unexpected,
                            "Note Board Plus exception on sending alert. Exception name: {0}. Exception message:{1}. Stack trace: {2}",
                            ex.GetType().FullName, ex.Message, ex.StackTrace);
                    }
                }
            }            
        }
    }
}